#ifndef __SPIN_LOCK_HPP__
#define __SPIN_LOCK_HPP__

#include <cstdint>
#include <atomic>
#include <thread>
#include <stdexcept>
#include <mutex>

/**
 * 使用原子操作制作而成的一个简易自旋锁
*/
class SingleSpinLock
{
public:
    SingleSpinLock() = default;
    ~SingleSpinLock() = default;

    SingleSpinLock(const SingleSpinLock & rhs) = delete;
    SingleSpinLock(SingleSpinLock && rhs) = delete;

    SingleSpinLock& operator=(const SingleSpinLock &rhs) = delete;
    SingleSpinLock& operator=(SingleSpinLock && rhs) = delete;

public:
    inline void lock()
    {
        while(m_lock.test_and_set(std::memory_order_acquire));
    }

    inline void unlock()
    {
        m_lock.clear(std::memory_order_release);
    }

private:
    std::atomic_flag m_lock = ATOMIC_FLAG_INIT;
};


// 用于debug时检测死锁
class SafeSpinLock
{
public:
    inline SafeSpinLock() : m_owner_thread_id(std::thread::id()) {}
    ~SafeSpinLock() = default;

    SafeSpinLock(const SafeSpinLock & rhs) = delete;
    SafeSpinLock(SafeSpinLock && rhs) = delete;

    SafeSpinLock& operator=(const SafeSpinLock &rhs) = delete;
    SafeSpinLock& operator=(SafeSpinLock && rhs) = delete;

public:
    inline void lock()
    {
        while(m_lock.test_and_set(std::memory_order_acquire))
        {
            if (m_owner_thread_id == std::this_thread::get_id())
            {
                throw std::runtime_error("不允许相同线程重复上锁");
            }
        }
        m_owner_thread_id = std::this_thread::get_id();
    }

    inline void unlock()
    {
        if (m_owner_thread_id != std::this_thread::get_id())
        {
            throw std::runtime_error("不允许不相同的线程进行解锁");
        }
        m_owner_thread_id = std::thread::id();
        m_lock.clear(std::memory_order_release);
    }

private:
    std::atomic_flag m_lock = ATOMIC_FLAG_INIT;
    std::thread::id m_owner_thread_id;              // 记录当前拥有锁的线程 ID
};




class Recursive_SpinLock
{
public:
    inline Recursive_SpinLock() : m_count(0), m_owner_thread_id(std::thread::id()) {}
    ~Recursive_SpinLock() = default;

    Recursive_SpinLock(const Recursive_SpinLock & rhs) = delete;
    Recursive_SpinLock(Recursive_SpinLock && rhs) = delete;

    Recursive_SpinLock& operator=(const Recursive_SpinLock &rhs) = delete;
    Recursive_SpinLock& operator=(Recursive_SpinLock && rhs) = delete;

public:
    inline void lock()
    {
        std::thread::id current_thread_id = std::this_thread::get_id();
        if (m_owner_thread_id == current_thread_id)
        {
            // 同一线程再次获取锁，增加计数即可
            m_count++;
            return;
        }
        while(m_lock.test_and_set(std::memory_order_acquire));

        // 获得锁后设置拥有者和计数
        m_owner_thread_id = current_thread_id;
        m_count = 1;
    }

    inline void unlock()
    {
        std::thread::id current_thread_id = std::this_thread::get_id();
        if (m_owner_thread_id != current_thread_id)
        {
            throw std::runtime_error("递归锁只允许同一线程下的多次解锁，其它线程不允许解锁");
        }
        if (--m_count == 0)
        {
            m_owner_thread_id = std::thread::id();
            m_lock.clear(std::memory_order_release);
        }
    }

private:
    std::atomic_flag m_lock = ATOMIC_FLAG_INIT;
    uint32_t m_count;                               // 记录当前线程已经锁定的次数
    std::thread::id m_owner_thread_id;              // 记录当前拥有锁的线程 ID
};



// 用于debug时检测死锁
class SafeMutex
{
public:
    inline SafeMutex() : m_owner_thread_id(std::thread::id()) {}
    ~SafeMutex() = default;

    SafeMutex(const SafeMutex & rhs) = delete;
    SafeMutex(SafeMutex && rhs) = delete;

    SafeMutex& operator=(const SafeMutex &rhs) = delete;
    SafeMutex& operator=(SafeMutex && rhs) = delete;

public:
    inline void lock()
    {
        std::thread::id current_thread_id = std::this_thread::get_id();
        if (m_mutex.try_lock())
        {
            goto lock;
        }
        if (m_owner_thread_id == current_thread_id)
        {
            throw std::runtime_error("不允许相同线程重复上锁");
        }
        m_mutex.lock();

    lock:
        m_owner_thread_id = current_thread_id;
    }

    inline void unlock()
    {
        if (m_owner_thread_id != std::this_thread::get_id())
        {
            throw std::runtime_error("不允许不相同的线程进行解锁");
        }
        m_mutex.unlock();
        m_owner_thread_id = std::thread::id();
    }

private:
    std::mutex m_mutex;
    std::thread::id m_owner_thread_id;              // 记录当前拥有锁的线程 ID
};




using SpinLock = SafeSpinLock;
using GameMutex = SafeMutex;


#endif
